<template>
  <div class="ai-task-container" style="display: inline-block;">
    <span v-if="showIcon" :title="title" @click="handleShowDialog">
      <svg-icon icon-class="ai-robot" style="font-size: 20px;" />
    </span>
    <el-button
      v-else
      :type="buttonType"
      size="mini"
      :icon="buttonIcon"
      @click="handleShowDialog"
    >{{ buttonText }}</el-button>

    <!-- AI分析对话框 -->
    <el-dialog
      :title="dialogTitle"
      :visible.sync="dialogVisible"
      append-to-body
      :width="dialogWidth"
      class="ai-dialog fullscreen-dialog"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <el-tabs v-model="activeTab">
        <el-tab-pane label="当前分析" name="current">
          <div>
            <!-- 任务开始前显示 -->
            <div v-if="!taskStarted" class="task-info">
              <div class="task-description">
                <i class="el-icon-info-circle" />
                <h3>{{ taskDisplayName || show_name || dialogTitle }}</h3>
                <p v-if="customInputHint">{{ customInputHint }}</p>
                <p v-else>点击下方"开始分析"按钮，AI将开始执行分析任务。</p>

                <!-- Tiptap编辑器输入区域（启用图片输入时） -->
                <div v-if="enableImageInput" class="image-input-section">
                  <!-- 已上传图片列表 -->
                  <div v-if="uploadedImages.length > 0" class="uploaded-images-grid">
                    <div v-for="image in uploadedImages" :key="image.uid" class="image-grid-item">
                      <div class="image-preview">
                        <img :src="image.file_url" :alt="image.display_name">
                      </div>
                      <div class="image-name">{{ image.display_name }}</div>
                      <el-button
                        type="danger"
                        size="mini"
                        icon="el-icon-delete"
                        circle
                        class="remove-image-btn"
                        @click="removeUploadedImage(image.uid)"
                      />
                    </div>
                  </div>

                  <label class="input-label">{{ imageInputLabel || '输入内容（支持粘贴图片）' }}：</label>
                  <tiptap-editor
                    ref="tiptapEditor"
                    v-model="user_content"
                    :height="150"
                    :placeholder="userContentPlaceholder || '可以直接粘贴图片，或输入文字描述...'"
                    :menubar="false"
                    :disable-image="false"
                    @image-uploaded="handleImageUploaded"
                  />

                  <!-- 上传按钮区域 -->
                  <div class="upload-actions">
                    <el-upload
                      class="upload-button"
                      :action="uploadUrl"
                      :headers="uploadHeaders"
                      :show-file-list="false"
                      accept="image/*"
                      :before-upload="beforeImageUpload"
                      :on-success="handleUploadSuccess"
                      :on-error="handleUploadError"
                      :data="uploadData"
                    >
                      <el-button size="small" type="text" icon="el-icon-upload2">
                        上传图片
                      </el-button>
                    </el-upload>

                    <el-button
                      size="small"
                      type="text"
                      icon="el-icon-link"
                      @click="showImageUrlDialog"
                    >
                      添加图片URL
                    </el-button>

                    <span class="upload-tip">或直接粘贴图片（Ctrl+V）、拖拽图片到编辑器</span>
                  </div>
                </div>

                <!-- 普通文本输入框（不启用图片时） -->
                <div v-else class="user-input-section">
                  <label class="input-label">{{ userContentLabel || '额外要求（可选）' }}：</label>
                  <el-input
                    v-model="user_content"
                    type="textarea"
                    :placeholder="userContentPlaceholder || '请输入您的额外要求或具体需求...'"
                    :rows="3"
                    class="user-content-input"
                  />
                </div>

                <el-button type="primary" @click="startAnalysis">发送处理</el-button>
              </div>
            </div>

            <!-- 思考状态 - chat_task的多轮对话不显示 -->
            <div v-else-if="isThinking && !isContinuousChat" class="ai-thinking">
              <div class="brain-animation">
                <div class="brain-container">
                  <div class="brain">
                    <div class="brain-part" />
                    <div class="brain-part" />
                    <div class="brain-part" />
                    <div class="brain-part" />
                  </div>
                  <div class="ai-thinking-text">AI正在思考中...</div>
                </div>
              </div>
            </div>
            <!-- 生成状态 - chat_task的多轮对话不显示 -->
            <div v-else-if="isTyping && !isContinuousChat" class="ai-indicator">
              <span class="typing-dots" />
            </div>
            <!-- 聊天对话区域 -->
            <div v-if="result || showChatHistory" ref="resultContainer" class="chat-container result-container">
              <!-- 滚动提示 -->
              <div v-if="userScrolled && !autoScrollEnabled" class="scroll-hint">
                <el-button
                  type="text"
                  size="mini"
                  icon="el-icon-arrow-down"
                  @click="scrollToBottom(true, true)"
                >
                  滚动到底部
                </el-button>
              </div>

              <!-- 对话历史记录 -->
              <div v-if="chatHistory.length > 0">
                <div v-for="(chat, index) in chatHistory" :key="'chat-' + index">
                  <!-- 用户消息 -->
                  <div class="chat-message user-message">
                    <div class="chat-bubble user-bubble">
                      {{ chat.user }}
                    </div>
                    <div class="chat-avatar user-avatar">
                      <i class="el-icon-user" />
                    </div>
                  </div>

                  <!-- AI回复 -->
                  <div v-if="chat.ai" class="chat-message ai-message" :class="{ 'has-code': hasHtmlCode(chat.ai) }">
                    <div class="chat-avatar ai-avatar">
                      <i class="el-icon-s-opportunity" />
                    </div>
                    <div class="chat-bubble ai-bubble" v-html="renderMarkdown(chat.ai)" />
                  </div>
                </div>

                <!-- 当前正在生成的AI回复（多轮对话模式） -->
                <div v-if="result && isGenerating" class="chat-message ai-message" :class="{ 'has-code': hasHtmlCode(result) }">
                  <div class="chat-avatar ai-avatar">
                    <i class="el-icon-s-opportunity" />
                  </div>
                  <div class="chat-bubble ai-bubble" v-html="renderMarkdown(result)" />
                </div>
              </div>

              <!-- 单轮对话显示（没有历史记录时） -->
              <template v-else-if="result && chatHistory.length === 0">
                <!-- 用户消息 -->
                <div v-if="user_content" class="chat-message user-message">
                  <div class="chat-bubble user-bubble">
                    {{ user_content }}
                  </div>
                  <div class="chat-avatar user-avatar">
                    <i class="el-icon-user" />
                  </div>
                </div>

                <!-- AI回复 -->
                <div class="chat-message ai-message" :class="{ 'has-code': hasHtmlCode(result) }">
                  <div class="chat-avatar ai-avatar">
                    <i class="el-icon-s-opportunity" />
                  </div>
                  <div class="chat-bubble ai-bubble" v-html="renderMarkdown(result)" />
                </div>
              </template>
            </div>

            <!-- 连续对话输入框 -->
            <div v-if="showContinueInput && !isGenerating" class="continue-chat-section">
              <div class="continue-chat-divider">
                <span>继续对话</span>
              </div>
              <!-- 显示当前对话状态 -->
              <div v-if="chatHistory.length > 0" class="chat-status">
                <span class="chat-status-text">
                  <i class="el-icon-chat-line-round" />
                  已进行 {{ chatHistory.length }} 轮对话
                </span>
              </div>
              <div class="continue-chat-input">
                <el-input
                  v-model="continueUserInput"
                  type="textarea"
                  placeholder="继续输入您的问题或要求..."
                  :rows="3"
                  class="continue-input"
                />
                <div class="continue-chat-actions">
                  <el-button
                    size="small"
                    :disabled="!continueUserInput.trim()"
                    type="primary"
                    @click="handleContinueChat"
                  >
                    发送
                  </el-button>
                  <el-button
                    size="small"
                    @click="endContinueChat"
                  >
                    结束对话
                  </el-button>
                </div>
              </div>
            </div>
          </div>
        </el-tab-pane>
        <el-tab-pane label="历史记录" name="history">
          <div class="history-list">
            <div v-if="history.length === 0" class="empty-history">
              <i class="el-icon-info" /> 暂无历史记录
            </div>
            <el-collapse v-else accordion>
              <el-collapse-item
                v-for="(item, index) in history"
                :key="index"
                :title="item.title || `分析记录 ${index + 1}`"
                :name="index"
              >
                <div class="history-item-content" v-html="renderMarkdown(item.content)" />
                <div class="history-item-time">{{ item.time }}</div>
                <div class="history-item-actions">
                  <el-button
                    type="text"
                    size="mini"
                    icon="el-icon-delete"
                    @click.stop="removeHistoryItem(index)"
                  >
                    删除
                  </el-button>
                  <el-button
                    type="text"
                    size="mini"
                    icon="el-icon-document-copy"
                    @click.stop="copyHistoryContent(item.content)"
                  >
                    复制
                  </el-button>
                </div>
              </el-collapse-item>
            </el-collapse>
          </div>
        </el-tab-pane>
      </el-tabs>
      <span slot="footer" class="dialog-footer">
        <el-button @click="closeDialog">关闭</el-button>
        <el-button
          v-if="!taskStarted && activeTab === 'current'"
          type="primary"
          @click="startAnalysis"
        >开始分析</el-button>
        <el-button
          v-if="showApplyButton && activeTab === 'current' && result"
          type="primary"
          @click="handleApply"
        >应用建议</el-button>
      </span>
    </el-dialog>

    <!-- 图片URL对话框 -->
    <el-dialog
      title="添加图片URL"
      :visible.sync="imageUrlDialogVisible"
      width="500px"
      append-to-body
    >
      <el-form ref="imageUrlForm" :model="imageUrlForm" :rules="imageUrlRules" label-width="100px">
        <el-form-item label="图片URL" prop="url">
          <el-input
            v-model="imageUrlForm.url"
            placeholder="请输入图片URL地址"
            clearable
          />
        </el-form-item>
        <el-form-item label="显示名称" prop="displayName">
          <el-input
            v-model="imageUrlForm.displayName"
            placeholder="可选，默认使用文件名"
            clearable
          />
        </el-form-item>
        <div class="url-tips">
          <p class="tip-title">📌 支持的图片格式：</p>
          <p class="tip-note">✓ JPG, JPEG, PNG, GIF, BMP, WEBP</p>
          <p class="tip-note">✓ 确保URL可以公开访问</p>
          <p class="tip-note">💡 提示：AI生成的图片可以直接复制URL添加为附件</p>
        </div>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="imageUrlDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="addImageUrl">添加</el-button>
      </span>
    </el-dialog>

  </div>
</template>

<script>
import MarkdownIt from 'markdown-it'
import { getToken } from '@/utils/auth'
import TiptapEditor from '@/components/Tiptap'

const HISTORY_STORAGE_KEY = 'ai_task_history'
const MAX_HISTORY_COUNT = 10

export default {
  name: 'AITask',
  components: {
    TiptapEditor
  },
  props: {
    // 参数配置
    params: {
      type: Object,
      default: () => ({})
    },
    // 任务名称（后端API使用的技术名称）
    taskName: {
      type: String,
      default: ''
    },
    // 任务显示名称（用户看到的友好名称，优先级最高）
    taskDisplayName: {
      type: String,
      default: ''
    },
    // 显示名称（用于显示友好的任务名称，尤其当taskName是代码片段时）
    show_name: {
      type: String,
      default: ''
    },
    // 自定义输入项名称
    customParamKey: {
      type: String,
      default: ''
    },
    // 对话框标题
    dialogTitle: {
      type: String,
      default: 'AI分析'
    },
    // 对话框宽度
    dialogWidth: {
      type: String,
      default: '50%'
    },
    // 是否显示应用按钮
    showApplyButton: {
      type: Boolean,
      default: true
    },
    // 是否显示图标而不是按钮
    showIcon: {
      type: Boolean,
      default: false
    },
    // 按钮类型
    buttonType: {
      type: String,
      default: 'primary'
    },
    // 按钮文本
    buttonText: {
      type: String,
      default: 'AI分析'
    },
    // 按钮图标
    buttonIcon: {
      type: String,
      default: 'el-icon-s-opportunity'
    },
    // 鼠标悬停提示
    title: {
      type: String,
      default: 'AI分析'
    },
    // 是否启用图片输入功能
    enableImageInput: {
      type: Boolean,
      default: false
    },
    // 图片输入标签文字
    imageInputLabel: {
      type: String,
      default: '图片输入'
    },
    // 自定义输入提示
    customInputHint: {
      type: String,
      default: ''
    },
    // 用户内容输入框标签
    userContentLabel: {
      type: String,
      default: '额外要求（可选）'
    },
    // 用户内容输入框占位符
    userContentPlaceholder: {
      type: String,
      default: '请输入您的额外要求或具体需求...'
    }
  },
  data() {
    return {
      // 基础状态
      dialogVisible: false,
      result: '',
      isGenerating: false,
      taskStarted: false,
      error: null,
      controller: null,
      timeoutId: null,
      final_result: '', // 保存最终结果
      receivedFirstChunk: false, // 是否收到第一块数据

      // 自动滚动相关
      userScrolled: false, // 用户是否主动滚动
      autoScrollEnabled: true, // 是否启用自动滚动
      lastScrollTop: 0, // 上次滚动位置
      scrollThreshold: 30, // 接近底部的阈值

      // 历史记录
      history: [],
      activeTab: 'current',

      // 连续对话相关
      isContinuousChat: false,
      chatMessages: [],
      showContinueInput: false,
      continueInput: '',
      showChatHistory: false, // 是否显示聊天历史
      chatHistory: [], // 聊天历史记录
      user_content: '', // 用户额外输入内容（Tiptap编辑器的HTML内容）
      uploadedImages: [], // 已上传的图片列表（作为附件）

      // 图片URL对话框
      imageUrlDialogVisible: false,
      imageUrlForm: {
        url: '',
        displayName: ''
      },
      imageUrlRules: {
        url: [
          { required: true, message: '请输入图片URL', trigger: 'blur' },
          { type: 'url', message: '请输入有效的URL地址', trigger: 'blur' }
        ]
      },

      // Markdown渲染器
      md: null
    }
  },
  computed: {
    // 获取请求头
    headers() {
      return {
        'Authorization': getToken(),
        'PTOKEN': this.$store.getters.projectId
      }
    },

    // 思考状态 - 还没收到任何数据时
    isThinking() {
      return this.isGenerating && !this.receivedFirstChunk && !this.result
    },

    // 打字状态 - 收到数据但还在生成中
    isTyping() {
      return this.isGenerating && this.receivedFirstChunk && !this.result
    },

    // 上传URL
    uploadUrl() {
      const baseUrl = process.env.VUE_APP_BASE_API || ''
      return baseUrl + '/crm/api/upload/'
    },

    // 上传headers
    uploadHeaders() {
      return {
        'Authorization': getToken(),
        'PTOKEN': this.$store.getters.projectId
      }
    },

    // 上传额外数据
    uploadData() {
      return {
        directory_id: 0
      }
    }
  },
  mounted() {
    // 初始化Markdown渲染器
    this.initializeMarkdown()

    // 从本地存储加载历史记录
    this.loadHistory()

    // 添加滚动事件监听
    this.addScrollListener()
  },

  beforeDestroy() {
    // 移除滚动事件监听
    this.removeScrollListener()

    // 取消任何正在进行的请求
    if (this.controller) {
      try {
        this.controller.abort('component_destroyed')
      } catch (error) {
        console.warn('中止请求时发生错误:', error)
      }
      this.controller = null
    }

    // 清除超时计时器
    if (this.timeoutId) {
      try {
        clearTimeout(this.timeoutId)
      } catch (error) {
        console.warn('清除计时器时发生错误:', error)
      }
      this.timeoutId = null
    }
  },

  updated() {
    // 组件更新后检查滚动容器并添加事件监听（防止refs延迟加载）
    this.addScrollListener()
  },
  created() {
    // 绑定代码运行事件
    this.bindCodeRunEvents()
    // 检查是否有初始messages参数
    this.checkInitialMessages()
  },
  methods: {
    // 重置状态
    resetState() {
      this.isGenerating = false
      this.result = ''
      this.final_result = ''
      this.receivedFirstChunk = false
      this.taskStarted = false
      this.activeTab = 'current'
      this.user_content = '' // 重置用户额外要求内容
      this.error = null

      // 重置连续对话状态
      this.isContinuousChat = false
      this.chatMessages = []
      this.chatHistory = []
      this.showContinueInput = false
      this.continueUserInput = ''

      // 重置滚动状态
      this.userScrolled = false
      this.autoScrollEnabled = true
      this.lastScrollTop = 0

      // 重置图片列表
      this.uploadedImages = []

      console.log('状态重置完成:', {
        taskName: this.taskName,
        taskStarted: this.taskStarted
      })
    },

    // 显示对话框
    handleShowDialog() {
      this.dialogVisible = true
      this.resetState()

      // 重新加载历史记录，确保显示最新的记录
      this.loadHistory()

      // 在下一个tick中添加滚动监听器，确保DOM已渲染
      this.$nextTick(() => {
        this.addScrollListener()
      })
    },

    // 开始分析任务
    async startAnalysis() {
      if (this.isGenerating) return

      this.taskStarted = true
      this.isGenerating = true
      this.result = ''
      this.final_result = ''
      this.receivedFirstChunk = false
      this.error = null

      // 重置滚动状态
      this.userScrolled = false
      this.autoScrollEnabled = true

      // 滚动到底部
      this.scrollToBottom()

      console.log('开始分析，参数:', {
        taskName: this.taskName,
        params: this.params,
        user_content: this.user_content,
        isGenerating: this.isGenerating,
        receivedFirstChunk: this.receivedFirstChunk
      })

      try {
        await this.performAnalysis()
      } catch (error) {
        this.error = error.message
        console.error('分析失败:', error)
      } finally {
        this.isGenerating = false
      }
    },

    // 关闭对话框
    closeDialog() {
      // 如果有进行中的请求，中断它
      if (this.controller) {
        this.controller.abort()
        this.controller = null
      }

      // 清除超时计时器
      if (this.timeoutId) {
        clearTimeout(this.timeoutId)
        this.timeoutId = null
      }

      // 如果有结果，保存到历史记录
      if (this.result) {
        this.saveToHistory()
      }

      this.dialogVisible = false
      this.$emit('close')
    },

    // 应用结果
    handleApply() {
      if (this.result) {
        // 传递完整的结果信息，包括final_result
        const resultData = {
          result: this.result,
          final_result: this.final_result,
          // 为了保持向后兼容，如果有final_result就优先使用，否则使用result
          content: this.final_result || this.result
        }
        this.$emit('apply', resultData)
        this.dialogVisible = false
      }
    },

    // 保存到历史记录
    saveToHistory() {
      // 创建历史记录项
      const historyItem = {
        title: (this.show_name || this.taskName || this.dialogTitle) + ' - ' + this.formatDate(new Date()),
        content: this.result,
        time: this.formatDate(new Date()),
        timestamp: Date.now()
      }

      // 添加到历史记录前面
      this.history.unshift(historyItem)

      // 限制历史记录数量
      if (this.history.length > MAX_HISTORY_COUNT) {
        this.history = this.history.slice(0, MAX_HISTORY_COUNT)
      }

      // 保存到本地存储
      this.saveHistory()
    },

    // 从本地存储加载历史记录
    loadHistory() {
      try {
        const historyJson = localStorage.getItem(HISTORY_STORAGE_KEY)
        if (historyJson) {
          this.history = JSON.parse(historyJson)
        }
      } catch (error) {
        console.error('加载历史记录失败:', error)
        this.history = []
      }
    },

    // 保存历史记录到本地存储
    saveHistory() {
      try {
        localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(this.history))
      } catch (error) {
        console.error('保存历史记录失败:', error)
      }
    },

    // 删除历史记录项
    removeHistoryItem(index) {
      this.history.splice(index, 1)
      this.saveHistory()
    },

    // 复制历史内容
    copyHistoryContent(content) {
      if (navigator.clipboard && navigator.clipboard.writeText) {
        navigator.clipboard.writeText(content).then(() => {
          this.$message.success('已复制到剪贴板')
        }).catch(err => {
          console.error('复制失败:', err)
          this.$message.error('复制失败')
        })
      } else {
        // 兼容不支持clipboard API的浏览器
        const textarea = document.createElement('textarea')
        textarea.value = content
        document.body.appendChild(textarea)
        textarea.select()
        document.execCommand('copy')
        document.body.removeChild(textarea)
        this.$message.success('已复制到剪贴板')
      }
    },

    // 格式化日期
    formatDate(date) {
      const year = date.getFullYear()
      const month = String(date.getMonth() + 1).padStart(2, '0')
      const day = String(date.getDate()).padStart(2, '0')
      const hours = String(date.getHours()).padStart(2, '0')
      const minutes = String(date.getMinutes()).padStart(2, '0')

      return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes
    },

    // 流式获取AI分析结果
    async fetchStreamResponse(data) {
      // 创建用于中断请求的控制器
      this.controller = new AbortController()
      const signal = this.controller.signal
      this.receivedFirstChunk = false

      console.log('请求开始前状态:', {
        isGenerating: this.isGenerating,
        receivedFirstChunk: this.receivedFirstChunk
      })

      // 设置初始超时
      this.timeoutId = setTimeout(() => {
        if (this.controller && !this.receivedFirstChunk) {
          this.controller.abort('initial_timeout')
        }
      }, 30000) // 30秒超时

      try {
        // 获取API基础URL
        const baseUrl = process.env.VUE_APP_BASE_API || ''

        // 发起流式请求
        const response = await fetch(baseUrl + '/crm/api/aitask/', {
          method: 'post',
          headers: {
            ...this.headers,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(data),
          signal: signal,
          mode: 'cors'
        })

        if (!response.ok) {
          throw new Error('HTTP error! status: ' + response.status)
        }

        // 获取响应的可读流
        const reader = response.body.getReader()
        const decoder = new TextDecoder('utf-8')
        let responseText = ''
        let bufferText = ''
        let isFinalResult = false // 标记是否进入最终结果模式
        this.final_result = '' // 重置最终结果

        // 流处理变量
        let streamingTimeoutId = null
        let lastUpdateTime = Date.now()
        let isMessagesMode = false // 标记是否进入messages解析模式
        let messagesBuffer = '' // messages数据缓冲区

        // 重置流超时函数
        const resetStreamingTimeout = () => {
          if (streamingTimeoutId) {
            clearTimeout(streamingTimeoutId)
          }

          streamingTimeoutId = setTimeout(() => {
            if (this.controller) {
              console.warn('流数据传输超时')
              this.controller.abort('streaming_timeout')
            }
          }, 15000) // 15秒超时
        }

        // 是否应该更新UI的判断函数
        const shouldUpdateUI = () => {
          const now = Date.now()
          if (now - lastUpdateTime > 100) { // 减小更新间隔，使打字效果更加平滑
            lastUpdateTime = now
            return true
          }
          return false
        }

        // 初始化流超时
        resetStreamingTimeout()

        // 处理流数据
        // eslint-disable-next-line no-constant-condition
        while (true) {
          try {
            const { done, value } = await reader.read()

            if (done) {
              // 处理剩余的缓冲区内容
              if (bufferText) {
                if (isMessagesMode) {
                // messages模式：只添加到messagesBuffer，不更新显示
                  messagesBuffer += bufferText
                  console.log('流结束：将剩余内容添加到messagesBuffer，不更新显示')
                } else if (isFinalResult) {
                  this.final_result += bufferText
                } else {
                // 正常模式：更新显示内容
                  this.result = responseText + bufferText
                }
              }

              // 处理messages数据
              if (isMessagesMode && messagesBuffer) {
                this.parseAndSetMessages(messagesBuffer)
              }

              break
            }

            // 标记已接收第一个数据块
            if (!this.receivedFirstChunk) {
              this.receivedFirstChunk = true
              console.log('收到第一个数据块，状态更新为:', {
                isGenerating: this.isGenerating,
                receivedFirstChunk: this.receivedFirstChunk
              })

              // 清除初始响应超时
              if (this.timeoutId) {
                clearTimeout(this.timeoutId)
                this.timeoutId = null
              }
            }

            // 重置流超时
            resetStreamingTimeout()

            // 解码数据
            const chunk = decoder.decode(value, { stream: true })

            // 添加到缓冲区
            bufferText += chunk

            // 检查是否包含messages标记
            const fullText = responseText + bufferText
            const messagesIndex = fullText.indexOf('{{messages}}')
            const finalResultIndex = fullText.indexOf('<!--FINAL_RESULT:')

            if (messagesIndex !== -1 && !isMessagesMode && !isFinalResult) {
              // 找到messages标记，切换到messages解析模式
              isMessagesMode = true

              // 提取标记前的内容作为最终显示内容，不再更新
              const displayContent = fullText.substring(0, messagesIndex)
              this.result = displayContent
              responseText = displayContent

              // 提取标记后的内容开始解析messages，但不显示
              const messagesContent = fullText.substring(messagesIndex + 12) // 12是"{{messages}}"的长度
              messagesBuffer = messagesContent
              bufferText = ''

              console.log('检测到{{messages}}标记，锁定显示内容，后续内容仅用于解析messages')

              // 滚动到底部
              this.scrollToBottom()
            } else if (isMessagesMode) {
              // 已经在messages解析模式，所有内容都添加到messagesBuffer，不更新UI显示
              messagesBuffer += bufferText
              bufferText = ''
              // 重要：不更新this.result，保持显示内容不变
            } else if (finalResultIndex !== -1 && !isFinalResult && !isMessagesMode) {
              // 找到最终结果标记，切换模式
              isFinalResult = true

              // 提取标记前的内容作为显示内容
              const displayContent = fullText.substring(0, finalResultIndex)
              this.result = displayContent
              responseText = displayContent

              // 提取标记后的内容作为最终结果
              const finalContent = fullText.substring(finalResultIndex + 17) // 17是"<!--FINAL_RESULT:"的长度
              this.final_result = this.cleanFinalResult(finalContent)
              bufferText = ''

              console.log('检测到最终结果标记，切换到最终结果模式')

              // 滚动到底部
              this.scrollToBottom()
            } else if (isFinalResult) {
              // 已经在最终结果模式，直接添加到final_result（不需要重复清理，只在最终输出时清理）
              this.final_result += bufferText
              bufferText = ''
            } else {
              // 正常模式，更新UI
              if (shouldUpdateUI()) {
                this.result = responseText + bufferText
                responseText += bufferText
                bufferText = ''

                // 每次更新UI后自动滚动到底部
                this.scrollToBottom()
              }
            }
          } catch (error) {
            console.error('读取流数据时出错:', error)

            if (error.name === 'AbortError') {
              // 请求被中止
              break
            }

            // 出现错误，等待后继续尝试
            await new Promise(resolve => setTimeout(resolve, 500))
          }
        }

        // 清理计时器
        if (streamingTimeoutId) {
          clearTimeout(streamingTimeoutId)
        }

        this.isGenerating = false

        // 将AI的回复添加到显示历史（包括第一次对话和连续对话）
        if (this.result && this.chatHistory.length > 0) {
          const lastChat = this.chatHistory[this.chatHistory.length - 1]
          if (lastChat && !lastChat.ai) {
            lastChat.ai = this.result
            console.log('将AI回复添加到显示历史:', this.result)
          }
        }

        // 如果是连续对话模式，显示继续对话输入框
        if (this.isContinuousChat) {
          this.showContinueInput = true
        }

        // 如果有最终结果，发送给父组件
        if (this.final_result) {
          // 最终清理一次结果
          const cleanedResult = this.cleanFinalResult(this.final_result)
          console.log('发送最终结果给父组件:', cleanedResult)
          this.$emit('final-result', cleanedResult)
        }
      } catch (error) {
        console.error('AI分析失败:', error)
        this.isGenerating = false

        if (error.name === 'AbortError') {
          if (error.message === 'initial_timeout') {
            this.result = '获取AI分析结果超时，请稍后再试'
          } else if (error.message === 'streaming_timeout') {
            // 如果已经有部分内容，保留它
            if (!this.result) {
              this.result = '获取AI分析结果时连接中断，请稍后再试'
            } else {
              this.result += '\\n\\n[连接中断，显示部分内容]'
            }
          }
        } else {
          this.result = '获取AI分析结果失败: ' + (error.message || '未知错误')
        }
      } finally {
        this.controller = null
      }
    },

    // 执行分析
    async performAnalysis() {
      // 确定用户输入内容：优先使用user_content，如果为空则使用show_name
      const userInput = this.user_content.trim() || this.show_name || ''

      // 如果是第一次对话且不是连续对话模式，添加用户输入到历史记录
      if (!this.isContinuousChat && userInput) {
        this.chatHistory.push({
          user: userInput,
          ai: '' // 等AI回复后再填充
        })
        console.log('第一次对话，添加用户输入到历史记录:', userInput)
      }

      // 构建请求参数
      let data = {}

      // 如果是chat_task且已有对话历史，使用精简参数
      if (this.taskName === 'chat_task' && this.chatMessages.length > 0) {
        data = {
          messages: this.chatMessages,
          show_name: this.show_name || 'AI对话',
          stream: true,
          task_name: this.taskName,
          user_content: this.user_content.trim()
        }
        console.log('chat_task多轮对话精简参数:', data)
      } else {
        // 首次对话或非chat_task，使用完整参数
        data = {
          task_name: this.taskName,
          stream: true,
          ...this.params
        }

        // 如果有show_name，也传递给后端
        if (this.show_name) {
          data.show_name = this.show_name
        }

        // 如果有用户额外要求，也传递给后端
        if (this.user_content && this.user_content.trim()) {
          data.user_content = this.user_content.trim()
        }

        // 如果有上传的图片附件，传递图片URL
        if (this.enableImageInput && this.uploadedImages.length > 0) {
          // 传递第一张图片的URL（大部分任务只需要一张图片）
          data.image_url = this.uploadedImages[0].file_url
        }

        // 如果是连续对话模式或者父组件传入了messages，传递对话历史
        if (this.isContinuousChat && this.chatMessages.length > 0) {
          data.messages = this.chatMessages
        } else if (this.params.messages && this.params.messages.length > 0) {
          data.messages = this.params.messages
        }

        console.log('首次对话或非chat_task完整参数:', data)
      }

      // 使用流模式获取AI分析结果
      await this.fetchStreamResponse(data)
    },

    // 开始分析

    // 清理最终结果中的注释标签
    cleanFinalResult(content) {
      if (!content) return ''

      let cleaned = content

      // 移除HTML注释标签 <!-- ... -->
      cleaned = cleaned.replace(/<!--[\s\S]*?-->/g, '')

      // 移除常见的标记符号
      cleaned = cleaned.replace(/-->/g, '')
      cleaned = cleaned.replace(/<!--/g, '')

      // 清理多余的空白字符
      cleaned = cleaned.trim()

      return cleaned
    },

    // 处理连续对话逻辑
    handleContinuousChatLogic() {
      // 只有当任务是chat_task时才启用连续对话
      if (this.taskName !== 'chat_task') {
        return
      }

      try {
        // 尝试从最终结果中解析messages参数
        if (this.final_result) {
          const parsedResult = this.parseMessagesFromResult(this.final_result)
          if (parsedResult && parsedResult.messages && Array.isArray(parsedResult.messages)) {
            this.isContinuousChat = true
            this.chatMessages = parsedResult.messages
            this.showContinueInput = true
            console.log('启用连续对话模式，messages:', parsedResult.messages)
          }
        }
      } catch (error) {
        console.error('解析连续对话参数失败:', error)
      }
    },

    // 滚动到底部 - 控制自动滚动的逻辑
    async scrollToBottom(waitForNextTick = true, force = false) {
      // 如果用户手动滚动且未滚动到底部，则不自动滚动（除非强制）
      if (!force && !this.autoScrollEnabled && this.userScrolled) {
        return
      }

      if (waitForNextTick) {
        await this.$nextTick()
      }

      // 查找结果显示区域
      const resultContainer = this.$refs.resultContainer ||
                             this.$el.querySelector('.result-container') ||
                             this.$el.querySelector('.el-dialog__body')

      if (resultContainer) {
        // 强制滚动到底部
        resultContainer.scrollTop = resultContainer.scrollHeight

        // 如果是强制滚动，重置滚动状态
        if (force) {
          this.userScrolled = false
          this.autoScrollEnabled = true
        }

        console.log('滚动到底部:', {
          scrollTop: resultContainer.scrollTop,
          scrollHeight: resultContainer.scrollHeight,
          clientHeight: resultContainer.clientHeight,
          force: force
        })
      }
    },

    // 处理用户滚动事件
    handleScroll(event) {
      const container = event.target
      if (!container) return

      // 计算是否在底部附近
      const isAtBottom = container.scrollHeight - container.scrollTop - container.clientHeight <= this.scrollThreshold

      // 确定滚动方向 (true = 向上, false = 向下)
      const isScrollingUp = container.scrollTop < this.lastScrollTop
      this.lastScrollTop = container.scrollTop

      // 用户向上滚动时，标记用户已滚动并禁用自动滚动
      if (isScrollingUp) {
        this.userScrolled = true
        this.autoScrollEnabled = false
      }

      // 用户滚动到底部时，启用自动滚动
      if (isAtBottom) {
        this.userScrolled = false
        this.autoScrollEnabled = true
      }
    },

    // 从结果中解析messages参数
    parseMessagesFromResult(result) {
      try {
        // 尝试将结果作为JSON解析
        const parsed = JSON.parse(result)
        return parsed
      } catch (e) {
        // 如果不是有效的JSON，尝试寻找JSON片段
        const jsonMatch = result.match(/\{[\s\S]*"messages"[\s\S]*\}/g)
        if (jsonMatch && jsonMatch.length > 0) {
          try {
            return JSON.parse(jsonMatch[0])
          } catch (e2) {
            console.warn('无法解析JSON片段:', jsonMatch[0])
          }
        }
      }
      return null
    },

    // 解析并设置messages数据
    parseAndSetMessages(messagesData) {
      try {
        console.log('开始解析messages数据:', messagesData)

        // 清理数据，移除可能的多余字符
        const cleanedData = messagesData.trim()

        // 尝试解析JSON
        const parsed = JSON.parse(cleanedData)

        if (Array.isArray(parsed)) {
          // 如果解析结果直接是数组，只保存用于后续请求，不用于显示
          this.chatMessages = parsed
          this.isContinuousChat = true
          this.showContinueInput = true
          console.log('成功解析messages数组，用于后续请求:', parsed)
        } else if (parsed && Array.isArray(parsed.messages)) {
          // 如果解析结果是对象，包含messages属性，只保存用于后续请求
          this.chatMessages = parsed.messages
          this.isContinuousChat = true
          this.showContinueInput = true
          console.log('成功解析messages对象，用于后续请求:', parsed.messages)
        } else {
          console.warn('解析的数据不是有效的messages格式:', parsed)
        }
      } catch (error) {
        console.error('解析messages数据失败:', error, 'raw data:', messagesData)

        // 尝试寻找JSON片段
        try {
          const jsonMatch = messagesData.match(/\[[\s\S]*\]/g)
          if (jsonMatch && jsonMatch.length > 0) {
            const parsed = JSON.parse(jsonMatch[0])
            if (Array.isArray(parsed)) {
              this.chatMessages = parsed
              this.isContinuousChat = true
              this.showContinueInput = true
              console.log('通过正则表达式成功解析messages，用于后续请求:', parsed)
              return
            }
          }
        } catch (e) {
          console.error('正则表达式解析也失败:', e)
        }
      }
    },

    // 处理继续对话
    handleContinueChat() {
      if (!this.continueUserInput.trim()) {
        return
      }

      // 保存用户输入内容
      const currentUserInput = this.continueUserInput.trim()

      // 只添加到显示用的对话历史（保存用户真实输入）
      this.chatHistory.push({
        user: currentUserInput,
        ai: '' // 等AI回复后再填充
      })

      this.continueUserInput = ''

      // 隐藏继续输入框
      this.showContinueInput = false

      // 重新开始分析 - 多轮对话时保持历史记录
      this.isGenerating = true
      this.showChatHistory = true // 显示聊天历史
      this.result = '' // 清空当前生成结果，准备接收新的回复
      this.receivedFirstChunk = true // 设置为true避免显示思考状态

      // 构建请求参数 - 直接使用后端返回的chatMessages，不做任何修改
      const data = {
        task_name: this.taskName,
        stream: true,
        messages: this.chatMessages, // 后端返回的原始messages，前端不修改
        show_name: this.show_name || 'AI对话',
        user_content: currentUserInput // 用户真实输入
      }

      console.log('继续对话请求参数:', data)

      // 使用流模式获取AI分析结果
      this.fetchStreamResponse(data)
    },

    // 结束继续对话
    endContinueChat() {
      this.showContinueInput = false
      this.isContinuousChat = false
      this.continueUserInput = ''
      // 保存到历史记录
      if (this.result) {
        this.saveToHistory()
      }
    },

    // 渲染Markdown内容
    renderMarkdown(content) {
      try {
        // 先处理HTML代码，将其转换为代码块
        let processedContent = this.processHtmlCode(content)

        // 处理特殊格式的图片链接
        processedContent = this.processImageLinks(processedContent)

        // 配置markdown-it
        const md = new MarkdownIt({
          html: true,
          breaks: true,
          linkify: true,
          typographer: false
        })

        // 添加插件处理链接，使其在新窗口打开并添加颜色样式
        md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
          const token = tokens[idx]
          token.attrPush(['target', '_blank'])
          token.attrPush(['rel', 'noopener noreferrer'])
          token.attrPush(['style', 'color: #409EFF !important; text-decoration: underline !important;'])
          return self.renderToken(tokens, idx, options)
        }

        // 图片添加css样式自适应宽度
        md.renderer.rules.image = (tokens, idx, options, env, self) => {
          const token = tokens[idx]
          token.attrPush(['style', 'max-width: 100%; height: auto; display: block; margin: 10px 0; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1);'])
          token.attrPush(['loading', 'lazy'])
          return self.renderToken(tokens, idx, options)
        }

        // 自定义代码块渲染，添加运行按钮
        md.renderer.rules.code_block = (tokens, idx, options, env, self) => {
          const token = tokens[idx]
          const content = token.content

          if (this.isHtmlCode(content)) {
            const codeId = 'code_' + Math.random().toString(36).substr(2, 9)
            return '<div class="html-code-block">' +
              '<pre><code class="language-html">' + this.escapeHtml(content) + '</code></pre>' +
              '<button class="run-code-btn" onclick="window.runHtmlCode(\'' + codeId + '\')">' +
                '<i class="el-icon-video-play"></i> 运行预览' +
              '</button>' +
              '<textarea id="' + codeId + '" style="display:none;">' + this.escapeHtml(content) + '</textarea>' +
            '</div>'
          }

          return '<pre><code>' + this.escapeHtml(content) + '</code></pre>'
        }

        // 自定义围栏代码块渲染
        md.renderer.rules.fence = (tokens, idx, options, env, self) => {
          const token = tokens[idx]
          const info = token.info ? token.info.trim() : ''
          const content = token.content

          if (info === 'html' || this.isHtmlCode(content)) {
            const codeId = 'code_' + Math.random().toString(36).substr(2, 9)
            return '<div class="html-code-block">' +
              '<pre><code class="language-html">' + this.escapeHtml(content) + '</code></pre>' +
              '<button class="run-code-btn" onclick="window.runHtmlCode(\'' + codeId + '\')">' +
                '<i class="el-icon-video-play"></i> 运行预览' +
              '</button>' +
              '<textarea id="' + codeId + '" style="display:none;">' + this.escapeHtml(content) + '</textarea>' +
            '</div>'
          }

          return '<pre><code class="language-' + info + '">' + this.escapeHtml(content) + '</code></pre>'
        }

        const rendered = md.render(processedContent || '')

        // 在下一个tick中绑定事件处理器
        this.$nextTick(() => {
          this.bindCodeRunEvents()
        })

        return `<div class="markdown-content">${rendered}</div>`
      } catch (error) {
        console.error('Markdown渲染失败:', error)
        // 失败时返回原始内容，确保内容不会丢失
        return content
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/\\n/g, '<br>')
      }
    },

    // 处理图片链接，直接匹配所有图片地址并显示为图片
    processImageLinks(content) {
      if (!content) return content

      // 匹配所有图片链接（以常见图片扩展名结尾的链接）
      const imageRegex = /(https?:\/\/[^\s]+\.(?:jpg|jpeg|png|webp|gif|svg))(?:\?[^\s]*)?/gi

      content = content.replace(imageRegex, (match, url) => {
        const fileName = url.split('/').pop().split('?')[0] // 去掉可能的查询参数
        return '![' + fileName + '](' + url + ')'
      })

      return content
    },

    // 处理HTML代码，将完整的HTML文档转换为代码块
    processHtmlCode(content) {
      if (!content) return content

      // 首先移除{{messages}}标记及其后面的所有内容
      const messagesIndex = content.indexOf('{{messages}}')
      if (messagesIndex !== -1) {
        content = content.substring(0, messagesIndex)
        console.log('在processHtmlCode中移除messages标记后的内容')
      }

      // 检测是否包含完整的HTML文档结构
      const htmlDocRegex = /<!DOCTYPE\s+html[\s\S]*?<html[\s\S]*?<\/html>/gi

      return content.replace(htmlDocRegex, (match) => {
        return '\\n```html\\n' + match + '\\n```\\n'
      })
    },

    // 检测是否是HTML代码
    isHtmlCode(content) {
      if (!content) return false

      // 检测HTML标签
      const htmlTagRegex = /<\s*(\w+)(\s+[^>]*)?\s*>/
      const hasHtmlTags = htmlTagRegex.test(content)

      // 检测DOCTYPE声明
      const hasDoctypeDeclaration = /<!DOCTYPE\s+html/i.test(content)

      // 检测常见的HTML结构标签
      const hasHtmlStructure = /<(html|head|body|title|meta|link|script|style)/i.test(content)

      return hasDoctypeDeclaration || hasHtmlStructure || (hasHtmlTags && content.length > 50)
    },

    // 检测内容是否包含HTML代码（用于模板）
    hasHtmlCode(content) {
      if (!content) return false

      // 检测是否包含HTML相关内容
      return content.includes('<!DOCTYPE') ||
             content.includes('<html') ||
             content.includes('<head') ||
             content.includes('<body') ||
             content.includes('```html') ||
             /html-code-block/.test(content)
    },

    // 检查初始messages参数
    checkInitialMessages() {
      if (this.params.messages && Array.isArray(this.params.messages) && this.params.messages.length > 0) {
        // 只保存后端返回的messages用于后续请求，不用于显示
        this.chatMessages = this.params.messages
        this.isContinuousChat = true
        console.log('初始化时检测到messages参数，用于后续请求:', this.params.messages)
      }
    },

    // 转义HTML字符
    escapeHtml(text) {
      const div = document.createElement('div')
      div.textContent = text
      return div.innerHTML
    },

    // 绑定代码运行事件
    bindCodeRunEvents() {
      // 全局函数，用于运行HTML代码
      window.runHtmlCode = (codeId) => {
        const textarea = document.getElementById(codeId)
        if (textarea) {
          const htmlCode = textarea.value
          this.previewHtmlCode(htmlCode)
        }
      }
    },

    // 预览HTML代码
    previewHtmlCode(htmlCode) {
      // 创建预览对话框
      this.$alert('', 'HTML代码预览', {
        dangerouslyUseHTMLString: true,
        message: '<div style="border: 1px solid #dcdfe6; border-radius: 4px; overflow: hidden;">' +
          '<div style="background-color: #f5f7fa; padding: 8px 12px; border-bottom: 1px solid #dcdfe6; font-size: 12px; color: #909399;">' +
            '预览效果' +
          '</div>' +
          '<iframe ' +
            'srcdoc="' + this.escapeHtml(htmlCode) + '" ' +
            'style="width: 100%; height: 400px; border: none;" ' +
            'sandbox="allow-scripts allow-same-origin">' +
          '</iframe>' +
        '</div>',
        confirmButtonText: '关闭',
        callback: () => {}
      })
    },

    // 初始化Markdown渲染器
    initializeMarkdown() {
      this.md = new MarkdownIt({
        html: true,
        breaks: true,
        linkify: true,
        typographer: false
      })

      // 添加插件处理链接，使其在新窗口打开并添加颜色样式
      this.md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        token.attrPush(['target', '_blank'])
        token.attrPush(['rel', 'noopener noreferrer'])
        token.attrPush(['style', 'color: #409EFF !important; text-decoration: underline !important;'])
        return self.renderToken(tokens, idx, options)
      }

      // 图片添加css样式自适应宽度
      this.md.renderer.rules.image = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        token.attrPush(['style', 'max-width: 100%; height: auto; display: block; margin: 10px 0; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1);'])
        token.attrPush(['loading', 'lazy'])
        return self.renderToken(tokens, idx, options)
      }

      // 自定义代码块渲染，添加运行按钮
      this.md.renderer.rules.code_block = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        const content = token.content

        if (this.isHtmlCode(content)) {
          const codeId = 'code_' + Math.random().toString(36).substr(2, 9)
          return '<div class="html-code-block">' +
            '<pre><code class="language-html">' + this.escapeHtml(content) + '</code></pre>' +
            '<button class="run-code-btn" onclick="window.runHtmlCode(\'' + codeId + '\')">' +
              '<i class="el-icon-video-play"></i> 运行预览' +
            '</button>' +
            '<textarea id="' + codeId + '" style="display:none;">' + this.escapeHtml(content) + '</textarea>' +
          '</div>'
        }

        return '<pre><code>' + this.escapeHtml(content) + '</code></pre>'
      }

      // 自定义围栏代码块渲染
      this.md.renderer.rules.fence = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        const info = token.info ? token.info.trim() : ''
        const content = token.content

        if (info === 'html' || this.isHtmlCode(content)) {
          const codeId = 'code_' + Math.random().toString(36).substr(2, 9)
          return '<div class="html-code-block">' +
            '<pre><code class="language-html">' + this.escapeHtml(content) + '</code></pre>' +
            '<button class="run-code-btn" onclick="window.runHtmlCode(\'' + codeId + '\')">' +
              '<i class="el-icon-video-play"></i> 运行预览' +
            '</button>' +
            '<textarea id="' + codeId + '" style="display:none;">' + this.escapeHtml(content) + '</textarea>' +
          '</div>'
        }

        return '<pre><code class="language-' + info + '">' + this.escapeHtml(content) + '</code></pre>'
      }

      // 添加插件处理链接，使其在新窗口打开并添加颜色样式
      this.md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        token.attrPush(['target', '_blank'])
        token.attrPush(['rel', 'noopener noreferrer'])
        token.attrPush(['style', 'color: #409EFF !important; text-decoration: underline !important;'])
        return self.renderToken(tokens, idx, options)
      }

      // 图片添加css样式自适应宽度
      this.md.renderer.rules.image = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        token.attrPush(['style', 'max-width: 100%; height: auto; display: block; margin: 10px 0; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1);'])
        token.attrPush(['loading', 'lazy'])
        return self.renderToken(tokens, idx, options)
      }

      // 自定义代码块渲染，添加运行按钮
      this.md.renderer.rules.code_block = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        const content = token.content

        if (this.isHtmlCode(content)) {
          const codeId = 'code_' + Math.random().toString(36).substr(2, 9)
          return '<div class="html-code-block">' +
            '<pre><code class="language-html">' + this.escapeHtml(content) + '</code></pre>' +
            '<button class="run-code-btn" onclick="window.runHtmlCode(\'' + codeId + '\')">' +
              '<i class="el-icon-video-play"></i> 运行预览' +
            '</button>' +
            '<textarea id="' + codeId + '" style="display:none;">' + this.escapeHtml(content) + '</textarea>' +
          '</div>'
        }

        return '<pre><code>' + this.escapeHtml(content) + '</code></pre>'
      }

      // 自定义围栏代码块渲染
      this.md.renderer.rules.fence = (tokens, idx, options, env, self) => {
        const token = tokens[idx]
        const info = token.info ? token.info.trim() : ''
        const content = token.content

        if (info === 'html' || this.isHtmlCode(content)) {
          const codeId = 'code_' + Math.random().toString(36).substr(2, 9)
          return '<div class="html-code-block">' +
            '<pre><code class="language-html">' + this.escapeHtml(content) + '</code></pre>' +
            '<button class="run-code-btn" onclick="window.runHtmlCode(\'' + codeId + '\')">' +
              '<i class="el-icon-video-play"></i> 运行预览' +
            '</button>' +
            '<textarea id="' + codeId + '" style="display:none;">' + this.escapeHtml(content) + '</textarea>' +
          '</div>'
        }

        return '<pre><code class="language-' + info + '">' + this.escapeHtml(content) + '</code></pre>'
      }
    },

    // 添加滚动事件监听
    addScrollListener() {
      // 优先使用resultContainer，如果没有则使用dialog body
      const scrollContainer = this.$refs.resultContainer || this.$el.querySelector('.el-dialog__body')
      if (scrollContainer && !scrollContainer._scrollListenerAdded) {
        scrollContainer.addEventListener('scroll', this.handleScroll)
        scrollContainer._scrollListenerAdded = true
      }
    },

    // 移除滚动事件监听
    removeScrollListener() {
      const scrollContainer = this.$refs.resultContainer || this.$el.querySelector('.el-dialog__body')
      if (scrollContainer && scrollContainer._scrollListenerAdded) {
        scrollContainer.removeEventListener('scroll', this.handleScroll)
        scrollContainer._scrollListenerAdded = false
      }
    },

    // ========== 图片输入相关方法 ==========

    // Tiptap编辑器图片上传成功回调
    handleImageUploaded(imageData) {
      console.log('Tiptap图片上传成功:', imageData)

      // 兼容不同的返回格式
      const imageUrl = imageData.url || imageData
      if (!imageUrl) return

      const timestamp = new Date().getTime()
      const uid = `tiptap_${timestamp}`

      // 从URL中提取文件名
      const urlParts = imageUrl.split('/')
      const fileName = urlParts[urlParts.length - 1] || `image_${timestamp}.png`

      // 添加到图片附件列表
      this.uploadedImages.push({
        original_name: fileName,
        display_name: fileName,
        file_name: fileName,
        file_url: imageUrl,
        uid: uid,
        size: imageData.size || 0
      })

      this.$message.success('图片已添加到附件')

      // 从编辑器中移除插入的图片（因为我们用附件展示）
      this.$nextTick(() => {
        // 手动清理HTML中的图片标签
        this.user_content = this.user_content.replace(/<img[^>]*>/gi, '')
      })
    },

    // 移除已上传的图片
    removeUploadedImage(uid) {
      const index = this.uploadedImages.findIndex(img => img.uid === uid)
      if (index > -1) {
        this.uploadedImages.splice(index, 1)
        this.$message.info('已移除图片')
      }
    },

    // 上传按钮：图片上传前的钩子
    beforeImageUpload(file) {
      const isImage = file.type.startsWith('image/')
      const isLt5M = file.size / 1024 / 1024 < 5

      if (!isImage) {
        this.$message.error('只能上传图片文件!')
        return false
      }
      if (!isLt5M) {
        this.$message.error('图片大小不能超过 5MB!')
        return false
      }
      return true
    },

    // 上传按钮：图片上传成功
    handleUploadSuccess(response, file) {
      if (response.success) {
        const timestamp = new Date().getTime()
        const uid = `upload_${timestamp}`

        this.uploadedImages.push({
          original_name: file.name,
          display_name: file.name,
          file_name: file.name,
          file_url: response.data.file_url,
          uid: uid,
          size: file.size
        })

        this.$message.success('图片上传成功')
      } else {
        this.$message.error(response.msg || '图片上传失败')
      }
    },

    // 上传按钮：图片上传失败
    handleUploadError() {
      this.$message.error('图片上传失败，请重试')
    },

    // 显示图片URL对话框
    showImageUrlDialog() {
      this.imageUrlDialogVisible = true
      this.imageUrlForm = {
        url: '',
        displayName: ''
      }
    },

    // 添加图片URL
    addImageUrl() {
      this.$refs.imageUrlForm.validate((valid) => {
        if (valid) {
          const timestamp = new Date().getTime()
          const uid = `url_${timestamp}`

          // 从URL中提取文件名
          const urlParts = this.imageUrlForm.url.split('/')
          const fileName = urlParts[urlParts.length - 1] || `image_${timestamp}.png`
          const displayName = this.imageUrlForm.displayName || fileName

          this.uploadedImages.push({
            original_name: fileName,
            display_name: displayName,
            file_name: fileName,
            file_url: this.imageUrlForm.url,
            uid: uid,
            size: 0
          })

          this.imageUrlDialogVisible = false
          this.$message.success('图片URL已添加')
        }
      })
    }
  }
}
</script>

<style scoped>
.ai-task-container {
  margin-right: 5px;
}

/* 任务信息显示样式 */
.task-info {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 30px 20px;
  min-height: 200px;
}

.task-description {
  text-align: center;
  background-color: #f9f9f9;
  border-radius: 8px;
  padding: 30px;
  width: 100%;
  max-width: 600px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}

.task-description i {
  font-size: 36px;
  color: #409EFF;
  margin-bottom: 15px;
}

.task-description h3 {
  margin: 15px 0;
  color: #303133;
  font-size: 18px;
}

.task-description p {
  color: #606266;
  margin-bottom: 20px;
  line-height: 1.6;
}

.task-description .el-button {
  margin-top: 10px;
  padding: 12px 25px;
  font-size: 16px;
}

/* 用户输入区域样式 */
.user-input-section {
  margin: 20px 0;
  text-align: left;
}

.input-label {
  display: block;
  margin-bottom: 8px;
  color: #606266;
  font-size: 14px;
  font-weight: 500;
}

.user-content-input {
  width: 100%;
}

.user-content-input >>> .el-textarea__inner {
  border-radius: 6px;
  border: 1px solid #dcdfe6;
  background-color: #fff;
  transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
}

.user-content-input >>> .el-textarea__inner:focus {
  border-color: #409EFF;
}

/* 新增设置Dialog顶部显示的样式 */
.ai-dialog >>> .el-dialog {
  margin-top: 0 !important;
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
  max-height: 100vh;
}

.ai-dialog >>> .el-dialog__body {
  overflow: auto;
  flex: 1;
}

/* AI思考中动画 */
.ai-thinking {
  text-align: center;
  padding: 30px 0;
  height: 120px;
}

.brain-animation {
  display: inline-block;
}

.brain-container {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.brain {
  width: 60px;
  height: 60px;
  position: relative;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-bottom: 10px;
}

.brain-part {
  width: 25px;
  height: 25px;
  background-color: #409EFF;
  margin: 2px;
  border-radius: 5px;
  opacity: 0.2;
  animation: brain-pulse 2s infinite;
}

.brain-part:nth-child(1) {
  animation-delay: 0s;
}

.brain-part:nth-child(2) {
  animation-delay: 0.3s;
}

.brain-part:nth-child(3) {
  animation-delay: 0.6s;
}

.brain-part:nth-child(4) {
  animation-delay: 0.9s;
}

@keyframes brain-pulse {
  0%, 100% {
    opacity: 0.2;
  }
  50% {
    opacity: 0.8;
  }
}

.ai-thinking-text {
  color: #409EFF;
  font-size: 14px;
  margin-top: 5px;
  font-weight: bold;
}

/* AI生成指示器样式 */
.ai-indicator {
  text-align: center;
  padding: 20px;
  height: 40px;
}

.typing-dots {
  display: inline-block;
  position: relative;
  width: 60px;
  height: 30px;
}

.typing-dots:before {
  content: '...';
  position: absolute;
  left: 0;
  right: 0;
  color: #409EFF;
  font-size: 24px;
  letter-spacing: 2px;
  animation: dots 1.5s infinite;
}

@keyframes dots {
  0%, 20% {
    content: '.';
  }
  40% {
    content: '..';
  }
  60%, 100% {
    content: '...';
  }
}

/* 聊天对话容器 */
.chat-container {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  line-height: 1.4;
}

/* 聊天消息布局 */
.chat-message {
  display: flex;
  margin-bottom: 16px;
  align-items: flex-start;
}

.user-message {
  flex-direction: row-reverse;
  justify-content: flex-start;
}

.ai-message {
  flex-direction: row;
  justify-content: flex-start;
}

/* 聊天气泡 */
.chat-bubble {
  max-width: 75%;
  padding: 10px 14px;
  border-radius: 18px;
  font-size: 14px;
  line-height: 1.4;
  word-break: break-word;
  white-space: pre-wrap;
}

/* HTML代码块容器扩大显示区域 */
.ai-bubble >>> .html-code-block {
  position: relative;
  margin: 12px -14px; /* 负边距扩展到气泡边缘 */
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid #e1e4e8;
  width: calc(100% + 28px); /* 补偿负边距 */
}

.user-bubble {
  background-color: #409EFF;
  color: white;
  margin-right: 8px;
  border-bottom-right-radius: 4px;
}

.ai-bubble {
  background-color: #f5f5f5;
  color: #333;
  margin-left: 8px;
  border-bottom-left-radius: 4px;
  animation: typing-cursor 0.5s step-end infinite alternate;
  word-wrap: break-word !important;
  word-break: break-word !important;
  overflow-wrap: break-word !important;
  hyphens: auto !important;
}

/* 包含HTML代码的AI消息使用更大宽度 */
.ai-message.has-code .chat-bubble {
  max-width: 90%;
}

/* 头像样式 */
.chat-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  flex-shrink: 0;
}

.user-avatar {
  background-color: #409EFF;
  color: white;
}

.ai-avatar {
  background-color: #e4e4e4;
  color: #666;
}

/* AI气泡内的markdown样式 */
.ai-bubble >>> pre {
  background-color: #f0f0f0;
  padding: 12px;
  border-radius: 8px;
  overflow-x: auto;
  margin: 8px 0;
}

.ai-bubble >>> code {
  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
  background-color: #f0f0f0;
  padding: 2px 4px;
  border-radius: 3px;
}

.ai-bubble >>> blockquote {
  border-left: 4px solid #409EFF;
  padding-left: 10px;
  color: #606266;
  margin: 10px 0;
}

.ai-bubble >>> table {
  border-collapse: collapse;
  width: 100%;
  margin: 12px 0;
}

.ai-bubble >>> table th,
.ai-bubble >>> table td {
  border: 1px solid #dcdfe6;
  padding: 8px;
  text-align: left;
}

.ai-bubble >>> table th {
  background-color: #f5f7fa;
}

.ai-bubble >>> a {
  color: #409EFF !important;
  text-decoration: underline !important;
  word-break: break-all !important;
  overflow-wrap: break-word !important;
  display: inline !important;
  max-width: 100% !important;
  white-space: normal !important;
  line-height: 1.4 !important;
}

/* 标题样式优化 */
.ai-bubble >>> h1 {
  font-size: 18px !important;
  margin: 10px 0 8px 0 !important;
  line-height: 1.3 !important;
  font-weight: 600 !important;
  color: #303133 !important;
}

.ai-bubble >>> h2 {
  font-size: 16px !important;
  margin: 8px 0 6px 0 !important;
  line-height: 1.3 !important;
  font-weight: 600 !important;
  color: #303133 !important;
}

.ai-bubble >>> h3 {
  font-size: 15px !important;
  margin: 8px 0 6px 0 !important;
  line-height: 1.3 !important;
  font-weight: 600 !important;
  color: #303133 !important;
}

.ai-bubble >>> h4 {
  font-size: 14px !important;
  margin: 6px 0 4px 0 !important;
  line-height: 1.3 !important;
  font-weight: 600 !important;
  color: #303133 !important;
}

.ai-bubble >>> h5 {
  font-size: 13px !important;
  margin: 6px 0 4px 0 !important;
  line-height: 1.3 !important;
  font-weight: 600 !important;
  color: #303133 !important;
}

.ai-bubble >>> h6 {
  font-size: 12px !important;
  margin: 6px 0 4px 0 !important;
  line-height: 1.3 !important;
  font-weight: 600 !important;
  color: #303133 !important;
}

/* 段落样式优化 */
.ai-bubble >>> p {
  font-size: 14px !important;
  line-height: 1.4 !important;
  margin: 6px 0 !important;
  color: #333 !important;
}

/* 列表样式优化 */
.ai-bubble >>> ul,
.ai-bubble >>> ol {
  margin: 6px 0 !important;
  padding-left: 20px !important;
  list-style-position: outside !important;
}

.ai-bubble >>> ul {
  list-style-type: disc !important;
}

.ai-bubble >>> ol {
  list-style-type: decimal !important;
}

.ai-bubble >>> li {
  font-size: 14px !important;
  line-height: 1.5 !important;
  margin: 3px 0 !important;
  word-break: break-word !important;
  overflow-wrap: break-word !important;
  white-space: normal !important;
  display: list-item !important;
}

/* 强调文本样式 */
.ai-bubble >>> strong {
  font-weight: 600 !important;
}

.ai-bubble >>> em {
  font-style: italic !important;
}

/* HTML代码块样式 */
.ai-bubble >>> .html-code-block pre {
  margin: 0;
  background-color: #f6f8fa;
  padding: 16px;
  overflow-x: auto;
  max-width: 100%;
}

.ai-bubble >>> .html-code-block code {
  background: none;
  padding: 0;
  font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', 'Source Code Pro', monospace;
  font-size: 12px;
  line-height: 1.5;
  color: #24292e;
  white-space: pre;
  word-break: normal;
  overflow-wrap: normal;
}

.ai-bubble >>> .run-code-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  background-color: #409EFF;
  color: white;
  border: none;
  border-radius: 4px;
  padding: 6px 12px;
  font-size: 12px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
  transition: background-color 0.2s;
  z-index: 1;
}

.ai-bubble >>> .run-code-btn:hover {
  background-color: #66b1ff;
}

.ai-bubble >>> .run-code-btn:active {
  background-color: #3a8ee6;
}

.ai-bubble >>> .run-code-btn i {
  font-size: 12px;
}

@keyframes typing-cursor {
  50% {
    border-right-color: transparent;
  }
}

.result-content >>> pre,
.history-item-content >>> pre {
  background-color: #f0f0f0;
  padding: 16px;
  border-radius: 4px;
  overflow-x: auto;
}

.result-content >>> code,
.history-item-content >>> code {
  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
  background-color: #f0f0f0;
  padding: 2px 4px;
  border-radius: 3px;
}

.result-content >>> blockquote,
.history-item-content >>> blockquote {
  border-left: 4px solid #409EFF;
  padding-left: 10px;
  color: #606266;
  margin: 10px 0;
}

.result-content >>> table,
.history-item-content >>> table {
  border-collapse: collapse;
  width: 100%;
  margin: 16px 0;
}

.result-content >>> table th,
.result-content >>> table td,
.history-item-content >>> table th,
.history-item-content >>> table td {
  border: 1px solid #dcdfe6;
  padding: 8px;
  text-align: left;
}

.result-content >>> table th,
.history-item-content >>> table th {
  background-color: #f5f7fa;
}

.empty-history {
  text-align: center;
  color: #909399;
  padding: 30px 0;
}

.history-list {
  max-height: 70vh;
  overflow-y: auto;
}

.history-item-content {
  padding: 10px;
  background-color: #f9f9f9;
  border-radius: 4px;
  max-height: 300px;
  overflow-y: auto;
}

.history-item-time {
  font-size: 12px;
  color: #909399;
  margin-top: 8px;
  text-align: right;
}

.history-item-actions {
  margin-top: 8px;
  text-align: right;
}

/* 连续对话样式 */
.continue-chat-section {
  margin-top: 20px;
  padding-top: 15px;
}

.continue-chat-divider {
  text-align: center;
  margin-bottom: 15px;
  position: relative;
}

.continue-chat-divider:before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 1px;
  background-color: #e4e7ed;
}

.continue-chat-divider span {
  background-color: #f9f9f9;
  padding: 0 15px;
  color: #909399;
  font-size: 12px;
  position: relative;
  z-index: 1;
}

.continue-chat-input {
  background-color: #f9f9f9;
  border-radius: 6px;
  padding: 15px;
  border: 1px solid #e4e7ed;
}

.continue-input {
  margin-bottom: 10px;
}

.continue-input >>> .el-textarea__inner {
  border-radius: 4px;
  border: 1px solid #dcdfe6;
  background-color: #fff;
}

.continue-input >>> .el-textarea__inner:focus {
  border-color: #409EFF;
}

.continue-chat-actions {
  text-align: right;
}

.continue-chat-actions .el-button {
  margin-left: 8px;
}

.chat-status {
  text-align: center;
  margin-bottom: 10px;
}

.chat-status-text {
  color: #909399;
  font-size: 12px;
  display: inline-flex;
  align-items: center;
}

.chat-status-text i {
  margin-right: 4px;
}

/* 结果容器样式 */
.result-container {
  max-height: calc(100vh - 200px) !important;
  overflow-y: auto;
  padding: 10px;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  background-color: #fafafa;
  position: relative;
}

.result-container::-webkit-scrollbar {
  width: 6px;
}

.result-container::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.result-container::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.result-container::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}

/* 滚动提示样式 */
.scroll-hint {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(64, 158, 255, 0.1);
  border: 1px solid #409eff;
  border-radius: 4px;
  padding: 5px;
  margin-bottom: 10px;
  text-align: center;
  animation: fadeIn 0.3s ease-in-out;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* 聊天容器样式 */
.chat-container {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  line-height: 1.4;
}

/* Markdown内容样式优化 */
.chat-bubble .markdown-content,
.chat-bubble p {
  margin: 0.5em 0 !important;
  line-height: 1.4 !important;
}

.chat-bubble .markdown-content h1,
.chat-bubble .markdown-content h2,
.chat-bubble .markdown-content h3,
.chat-bubble .markdown-content h4,
.chat-bubble .markdown-content h5,
.chat-bubble .markdown-content h6 {
  margin: 0.8em 0 0.4em 0 !important;
  line-height: 1.3 !important;
}

.chat-bubble .markdown-content ul,
.chat-bubble .markdown-content ol {
  margin: 0.5em 0 !important;
  padding-left: 1.5em !important;
}

.chat-bubble .markdown-content li {
  margin: 0.2em 0 !important;
  line-height: 1.4 !important;
}

.chat-bubble .markdown-content blockquote {
  margin: 0.5em 0 !important;
  padding: 0.5em 1em !important;
  border-left: 4px solid #ddd !important;
  background-color: #f9f9f9 !important;
}

.chat-bubble .markdown-content pre {
  margin: 0.5em 0 !important;
  padding: 1em !important;
  background-color: #f5f5f5 !important;
  border-radius: 4px !important;
  overflow-x: auto !important;
}

.chat-bubble .markdown-content code {
  padding: 0.2em 0.4em !important;
  background-color: #f5f5f5 !important;
  border-radius: 3px !important;
  font-size: 0.9em !important;
}

.chat-bubble .markdown-content table {
  margin: 0.5em 0 !important;
  border-collapse: collapse !important;
  width: 100% !important;
}

.chat-bubble .markdown-content th,
.chat-bubble .markdown-content td {
  padding: 0.4em 0.8em !important;
  border: 1px solid #ddd !important;
  text-align: left !important;
}

.chat-bubble .markdown-content th {
  background-color: #f5f5f5 !important;
  font-weight: bold !important;
}

/* 全屏对话框样式 */
.fullscreen-dialog {
  margin: 0 !important;
  width: 100% !important;
  height: 100% !important;
  max-width: none !important;
  max-height: none !important;
}

.fullscreen-dialog .el-dialog {
  margin: 0 !important;
  width: 100% !important;
  height: 100vh !important;
  max-width: none !important;
  max-height: none !important;
  border-radius: 0 !important;
  display: flex !important;
  flex-direction: column !important;
}

.fullscreen-dialog .el-dialog__header {
  padding: 15px 20px !important;
  border-bottom: 1px solid #e4e7ed !important;
  flex-shrink: 0 !important;
}

.fullscreen-dialog .el-dialog__body {
  flex: 1 !important;
  padding: 20px !important;
  overflow-y: auto !important;
  height: calc(100vh - 120px) !important;
}

.fullscreen-dialog .el-dialog__footer {
  padding: 15px 20px !important;
  border-top: 1px solid #e4e7ed !important;
  flex-shrink: 0 !important;
}

/* 图片输入区域样式 */
.image-input-section {
  margin: 20px 0;
  text-align: left;
}

.uploaded-images-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 15px;
}

.image-grid-item {
  position: relative;
  width: 120px;
  border: 2px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
  background-color: #f5f7fa;
  transition: all 0.3s;
}

.image-grid-item:hover {
  border-color: #409eff;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}

.image-preview {
  width: 100%;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #fff;
  overflow: hidden;
}

.image-preview img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.image-name {
  padding: 6px 8px;
  font-size: 12px;
  color: #606266;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background-color: #f5f7fa;
}

.remove-image-btn {
  position: absolute;
  top: 4px;
  right: 4px;
  background-color: rgba(245, 108, 108, 0.95) !important;
  border-color: rgba(245, 108, 108, 0.95) !important;
  padding: 4px !important;
  width: 24px !important;
  height: 24px !important;
}

.remove-image-btn:hover {
  background-color: rgba(245, 108, 108, 1) !important;
}

.upload-actions {
  margin-top: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.upload-button {
  display: inline-block;
}

.upload-tip {
  color: #909399;
  font-size: 12px;
  margin-left: auto;
}

/* URL对话框提示样式 */
.url-tips {
  margin-top: 15px;
  padding: 12px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

.tip-title {
  font-weight: 600;
  color: #303133;
  margin-bottom: 8px;
  font-size: 13px;
}

.tip-note {
  color: #606266;
  font-size: 12px;
  margin: 4px 0;
  line-height: 1.5;
}
</style>
